package com.learning.platform.util;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Component
public class JwtUtil {
    
    private static final Logger logger = LoggerFactory.getLogger(JwtUtil.class);
    
    @Value("${jwt.secret}")
    private String secret;
    
    @Value("${jwt.expiration}")
    private Long expiration;
    
    @Value("${jwt.refresh-expiration}")
    private Long refreshExpiration;
    
    private SecretKey getSigningKey() {
        try {
            // 检查密钥是否为空
            if (secret == null || secret.trim().isEmpty()) {
                logger.warn("JWT密钥未设置，使用默认密钥（仅适用于开发环境！生产环境必须设置密钥）");
                return Keys.hmacShaKeyFor("default-development-key-only-do-not-use-in-production-environment-this-must-be-64-characters-long".getBytes());
            }
            
            // 检查密钥长度，如果少于64字符，使用SHA-512哈希扩展
            if (secret.length() < 64) {
                logger.info("JWT密钥长度不足({} 字符)，使用SHA-512哈希扩展到安全长度", secret.length());
                java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-512");
                byte[] hash = md.digest(secret.getBytes());
                return Keys.hmacShaKeyFor(hash);
            }
            
            // 密钥长度足够，直接使用
            logger.debug("使用原始JWT密钥（长度: {} 字符）", secret.length());
            return Keys.hmacShaKeyFor(secret.getBytes());
            
        } catch (Exception e) {
            logger.error("创建JWT密钥失败，使用备用密钥: {}", e.getMessage());
            // 备用方案：使用固定的安全长度密钥（64字符以上）
            return Keys.hmacShaKeyFor("emergency-fallback-jwt-key-for-development-environment-only-change-in-production-this-is-64-chars".getBytes());
        }
    }
    
    /**
     * 生成访问令牌
     */
    public String generateAccessToken(Long userId, String username, String role) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userId);
        claims.put("username", username);
        claims.put("role", role);
        claims.put("type", "access");
        
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + expiration))
                .signWith(getSigningKey(), SignatureAlgorithm.HS512)
                .compact();
    }
    
    /**
     * 生成刷新令牌
     */
    public String generateRefreshToken(Long userId, String username) {
        Map<String, Object> claims = new HashMap<>();
        claims.put("userId", userId);
        claims.put("username", username);
        claims.put("type", "refresh");
        
        return Jwts.builder()
                .setClaims(claims)
                .setSubject(username)
                .setIssuedAt(new Date())
                .setExpiration(new Date(System.currentTimeMillis() + refreshExpiration))
                .signWith(getSigningKey(), SignatureAlgorithm.HS512)
                .compact();
    }
    
    /**
     * 解析令牌
     */
    public Claims parseToken(String token) {
        try {
            return Jwts.parserBuilder()
                    .setSigningKey(getSigningKey())
                    .build()
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException e) {
            logger.warn("JWT token expired: {}", token);
            throw e;
        } catch (UnsupportedJwtException e) {
            logger.error("JWT token unsupported: {}", token);
            throw e;
        } catch (MalformedJwtException e) {
            logger.error("JWT token malformed: {}", token);
            throw e;
        } catch (SecurityException e) {
            logger.error("JWT token signature invalid: {}", token);
            throw e;
        } catch (IllegalArgumentException e) {
            logger.error("JWT token illegal argument: {}", token);
            throw e;
        }
    }
    
    /**
     * 验证令牌是否有效
     */
    public boolean validateToken(String token) {
        try {
            parseToken(token);
            return true;
        } catch (JwtException e) {
            return false;
        }
    }
    
    /**
     * 从令牌中获取用户ID
     */
    public Long getUserIdFromToken(String token) {
        Claims claims = parseToken(token);
        return Long.valueOf(claims.get("userId").toString());
    }
    
    /**
     * 从令牌中获取用户名
     */
    public String getUsernameFromToken(String token) {
        Claims claims = parseToken(token);
        return claims.getSubject();
    }
    
    /**
     * 从令牌中获取角色
     */
    public String getRoleFromToken(String token) {
        Claims claims = parseToken(token);
        return (String) claims.get("role");
    }
    
    /**
     * 检查是否为刷新令牌
     */
    public boolean isRefreshToken(String token) {
        Claims claims = parseToken(token);
        return "refresh".equals(claims.get("type"));
    }
    
    /**
     * 检查令牌是否即将过期（1小时内）
     */
    public boolean isTokenExpiringSoon(String token) {
        Claims claims = parseToken(token);
        Date expiration = claims.getExpiration();
        long timeUntilExpiry = expiration.getTime() - System.currentTimeMillis();
        return timeUntilExpiry < 3600000; // 1小时
    }
}










